package com.example.satoken.service.impl;

import cn.dev33.satoken.secure.BCrypt;
import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.example.satoken.common.exception.BaseException;
import com.example.satoken.constants.UserConstants;
import com.example.satoken.entitry.User;
import com.example.satoken.enums.LoginType;
import com.example.satoken.mapper.UserMapper;
import com.example.satoken.model.RegisterBody;
import com.example.satoken.service.IUserService;
import com.example.satoken.util.FormValidatorUtils;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.function.Supplier;

@Service
@AllArgsConstructor
@Slf4j
public class IUserServiceImpl extends ServiceImpl<UserMapper, User> implements IUserService {

    private final UserMapper userMapper;

    /**
     * 登录验证
     *
     * @param username 用户名(多种方式: 邮箱,手机号,weChat,QQ)
     * @param password 密码
     * @param type     登录方式
     * @return 结果
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public String login(String username, String password, LoginType type) {

        User user = null;
        // email
        if (type == LoginType.EMAIL) {
            user = checkLogin(type, username, () -> FormValidatorUtils.validateEmail(username));
        }

        // phone
        if (type == LoginType.SMS) {
            user = checkLogin(type, username, () -> FormValidatorUtils.validatePhone(username));
        }

        // 校验密码
        if (!BCrypt.checkpw(password, user.getPassword())) {
            throw new BaseException("登录密码错误！");
        }
        // 满足登录条件的需要踢出对应的同端-其他登录。
        StpUtil.logout(user.getId());
        // 登入当前用户
        StpUtil.login(user.getId());
        //放入用户到Session会话
        StpUtil.getTokenSession().set(UserConstants.LOGIN_USER_KEY, user);
        // 返回token
        return StpUtil.getTokenValue();
    }

    /**
     * 注册账号
     *
     * @param registerBody
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public String register(RegisterBody registerBody) {
        String username = registerBody.getUsername();
        String password = registerBody.getPassword();
        User user = new User();
        if (FormValidatorUtils.validateEmail(username)) {
            user.setEmail(username);
        }
        if (FormValidatorUtils.validatePhone(username)) {
            user.setMobile(username);
        }
        Wrapper<User> eq = new LambdaQueryWrapper<User>(user);
        User dbUser = userMapper.selectOne(eq);
        if (ObjectUtil.isNotNull(dbUser)) {
            log.info("用户名已存在：{} 已存在.", username);
            throw new BaseException(username.concat(username + "用户名已存在：{} 已存在！"));
        }
        user.setPassword(BCrypt.hashpw(password));
        int insert = userMapper.insert(user);
        if (insert == 0) {
            throw new BaseException("user.register.error");
        }
        return "SUCCESS";
    }

    /**
     * 登录校验
     */
    private User checkLogin(LoginType loginType, String username, Supplier<Boolean> supplier) {
        if (!supplier.get()) {
            throw new BaseException(loginType.name().concat("校验格式错误！"));
        }
        // email
        if (loginType == LoginType.EMAIL) {
            return loadUserByEmail(username);
        }

        // phone
        if (loginType == LoginType.SMS) {
            return loadUserByPhoneNumber(username);
        }
        return null;
    }

    /**
     * 电话用户
     *
     * @param phone
     * @return
     */
    private User loadUserByPhoneNumber(String phone) {
        Wrapper<User> eq = new LambdaQueryWrapper<User>().eq(StrUtil.isNotBlank(phone), User::getMobile, phone);
        User user = userMapper.selectOne(eq);
        if (ObjectUtil.isNull(user)) {
            log.info("登录用户：{} 不存在.", phone);
            throw new BaseException(phone.concat(phone + "用户不存在,请先注册！"));
        }
        return user;
    }

    /**
     * 邮箱用户
     *
     * @param email
     * @return
     */
    private User loadUserByEmail(String email) {
        Wrapper<User> eq = new LambdaQueryWrapper<User>().eq(StrUtil.isNotBlank(email), User::getEmail, email);
        User user = userMapper.selectOne(eq);
        if (ObjectUtil.isNull(user)) {
            log.info("登录用户：{} 不存在.", email);
            throw new BaseException(email.concat(email + "用户不存在,请先注册！"));
        }
        return user;
    }
}
